﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace SuperBall3D
{
    class Player : DynamicSuperBallObject
    {
        KeyboardState previousKeyState;
        public float playerFacingDirection;
        bool readyToJump;
        SoundEffect bounceSound;

        public Player(Game g, Vector3 pos)
            : this(g, pos, 1f)
        {
        }

        public Player(Game g, Vector3 pos, float r)
            : base(g, false, pos, r * r * r, 1f, .7f)
        {
            Position = pos;
            readyToJump = false;
            RadiusScale = r;
        }

        protected override void LoadContent()
        {
            superBallModel = Game.Content.Load<Model>("Models\\beach ball");
            Geo = new Geometry(Geometry.GeometryType.Sphere, superBallModel, Position + CenterOffset, RadiusScale);
            bounceSound = Game.Content.Load<SoundEffect>("SoundEffects\\Boing-One Low");

            base.LoadContent();
        }




        public override void Initialize()
        {
            previousKeyState = Keyboard.GetState();
            max_speed = 800f;
            base.Initialize();
        }


        public override void Update(GameTime gameTime)
        {

            Camera.UpdateCam(gameTime, Position, playerFacingDirection);

           
            HandleInput(gameTime);


            base.Update(gameTime);

        }

        private Texture2D[] ChangeEffect(ref Model model, Effect newEffect)
        {
            List<Texture2D> texturelist = new List<Texture2D>();
            foreach (ModelMesh mesh in model.Meshes)
                foreach (ModelMeshPart modmeshpart in mesh.MeshParts)
                {
                    BasicEffect oldEffect = (BasicEffect)modmeshpart.Effect;
                    texturelist.Add(oldEffect.Texture);
                    modmeshpart.Effect = newEffect.Clone();
                }
            Texture2D[] textures = texturelist.ToArray();
            return textures;
        }


        private const float movement_accel = -50f;
        private const float turn_speed = 2f;
        private void HandleInput(GameTime gameTime)
        {
            KeyboardState currentKeyboardState = Keyboard.GetState();
            float totalSeconds = (float)gameTime.TotalGameTime.TotalSeconds;
            // instant brake
            if (currentKeyboardState.IsKeyDown(Keys.LeftShift))
            {
                Velocity = new Vector3(
                    Velocity.X / -1.2f,
                    Velocity.Y,
                    Velocity.Z / -1.2f);

            }


            float turnAmount = 0;

            if ((currentKeyboardState.IsKeyDown(Keys.A) || currentKeyboardState.IsKeyDown(Keys.Left)) &&
                !(currentKeyboardState.IsKeyDown(Keys.D) || currentKeyboardState.IsKeyDown(Keys.Right)))
                turnAmount += turn_speed;
            if ((currentKeyboardState.IsKeyDown(Keys.D) || currentKeyboardState.IsKeyDown(Keys.Right)) &&
                !(currentKeyboardState.IsKeyDown(Keys.A) || currentKeyboardState.IsKeyDown(Keys.Left)))
                turnAmount -= turn_speed;

            playerFacingDirection += turnAmount * Physics.deltaT;

            Vector3 movement = Vector3.Zero;

            // lets player move with some "starting" velocity
            if ((currentKeyboardState.IsKeyDown(Keys.W) || currentKeyboardState.IsKeyDown(Keys.Up)) &&
                !(currentKeyboardState.IsKeyDown(Keys.S) || currentKeyboardState.IsKeyDown(Keys.Down)))
            {
                if (!readyToJump) movement.Z = 6f * movement_accel;
                else if (previousKeyState.IsKeyUp(Keys.W) && previousKeyState.IsKeyUp(Keys.Up))
                    movement.Z = 10 * movement_accel;
                else movement.Z = movement_accel;
            }
            if ((currentKeyboardState.IsKeyDown(Keys.S) || currentKeyboardState.IsKeyDown(Keys.Down)) &&
                !(currentKeyboardState.IsKeyDown(Keys.W) || currentKeyboardState.IsKeyDown(Keys.Up)))
            {
                if (!readyToJump) movement.Z = -6f * movement_accel;
                else if (previousKeyState.IsKeyUp(Keys.S) && previousKeyState.IsKeyUp(Keys.Down))
                    movement.Z = -10 * movement_accel;
                else movement.Z = -movement_accel;
            }

            Matrix playerFacingMatrix = Matrix.CreateRotationY(playerFacingDirection);

            Acceleration += Vector3.Transform(movement, playerFacingMatrix);

            int rollDirection = Vector3.Dot(playerFacingMatrix.Forward, Velocity) < 0 ? 1 : -1;

            float distanceMoved = Vector3.Distance(PreviousPosition, Position); 
            float deltaTheta = distanceMoved / (100f * RadiusScale);

            RotationMatrix *= Matrix.CreateFromAxisAngle(playerFacingMatrix.Right, deltaTheta * rollDirection);

            if (currentKeyboardState.IsKeyDown(Keys.Space) && !previousKeyState.IsKeyDown(Keys.Space))
            {
                Jump();
            }
        }

        public override void Draw(GameTime gameTime)
        {
            Vector3 offset = Vector3.One * Geo.BSphere.Radius;
            base.Draw(gameTime);
        }

        // Custom functions
        private void Jump()
        {
            if (!readyToJump) return;
            bounceSound.Play();

            Acceleration += new Vector3(0, 28000, 0);

            readyToJump = false;

        }

        public bool ReadyToJump
        {
            get { return readyToJump; }
            set { readyToJump = value; }
        }

        public override string GenerateConstructor()
        {
            return "";
        }

    }
}